package cn.org.tpeach.nosql.service.impl;

import cn.org.tpeach.nosql.annotation.Component;
import cn.org.tpeach.nosql.bean.DicBean;
import cn.org.tpeach.nosql.controller.KeyInfoController;
import cn.org.tpeach.nosql.controller.MainController;
import cn.org.tpeach.nosql.controller.RedisApplication;
import cn.org.tpeach.nosql.controller.ServerInfoController;
import cn.org.tpeach.nosql.enums.RedisTreeType;
import cn.org.tpeach.nosql.framework.LarkFrame;
import cn.org.tpeach.nosql.framework.ServiceProxy;
import cn.org.tpeach.nosql.redis.bean.RedisConnectInfo;
import cn.org.tpeach.nosql.redis.bean.RedisTreeItem;
import cn.org.tpeach.nosql.redis.connection.RedisLarkPool;
import cn.org.tpeach.nosql.redis.controller.BaseController;
import cn.org.tpeach.nosql.redis.controller.ResultRes;
import cn.org.tpeach.nosql.redis.service.IRedisConfigService;
import cn.org.tpeach.nosql.redis.service.IRedisConnectService;
import cn.org.tpeach.nosql.service.ICommonService;
import cn.org.tpeach.nosql.tools.ConfigParserUtils;
import cn.org.tpeach.nosql.tools.DataStructureUtils;
import cn.org.tpeach.nosql.tools.GsonUtil;
import cn.org.tpeach.nosql.tools.StringUtils;
import cn.org.tpeach.nosql.view.JavaFxUtil;
import javafx.beans.value.ChangeListener;
import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;

import java.io.IOException;
import java.util.Iterator;
import java.util.Optional;

/**
 * @author tyz
 * @Title: CommonService
 * @ProjectName Redis-Lettuce-Parent
 * @Description: TODO
 * @date 2020-06-04 12:37
 * @since 1.0.0
 */
@Component("commonService")
public class CommonServiceImpl  implements ICommonService {
    private final IRedisConnectService redisConnectService = ServiceProxy.getBeanProxy("redisConnectService", IRedisConnectService.class);
    private final IRedisConfigService redisConfigService = ServiceProxy.getBeanProxy("redisConfigService", IRedisConfigService.class);

    @Override
    public void renameKey(TreeItem<RedisTreeItem> selectedItem, RedisTreeItem value){
        TextInputDialog dialog = new TextInputDialog(value.getName());
        dialog.setContentText("NEW NAME:");
        dialog.setTitle("Rename Key");
        dialog.setHeaderText(null);
        Optional<String> result = dialog.showAndWait();
        result.ifPresent(name ->{
            if(StringUtils.isNotBlank(name)){
                byte[] nameByte = ConfigParserUtils.getInstance().strToByte(name);
                ResultRes<Boolean> res = BaseController.dispatcher(() -> redisConnectService.remamenx( value.getId(), value.getDbAmount().getDbIndex(), value.getKey(), nameByte));
                if (!res.isRet()) {
                    JavaFxUtil.showMessageErrorDialog(LarkFrame.primaryStage,null,"Rename Failed: " + res.getMsg());
                } else if (!res.getData()) {
                    JavaFxUtil.showMessageErrorDialog(LarkFrame.primaryStage,null,"Rename Failed: Key with new name already exist in database or original key was removed");
                }else{
                    value.setKey(nameByte);
                    value.setName(name);
                    value.setOriginName(name);
                    Event.fireEvent(selectedItem, new TreeItem.TreeModificationEvent<>(TreeItem.valueChangedEvent(), selectedItem, selectedItem.getValue()));
                    ObservableList<Tab> tabs = RedisApplication.mainController.getMainInfoTabPane().getTabs();
                    if(DataStructureUtils.isNotEmpty(tabs)){
                        for (Tab tab : tabs) {
                            if(tab.getUserData() == value && "keyInfo".equals(tab.getProperties().get("type"))){
                               KeyInfoController keyInfoController = (KeyInfoController) tab.getProperties().get("controller");
                                keyInfoController.refresh();
                            }
                        }
                    }
                }
            }else{
                JavaFxUtil.showMessageErrorDialog(null,null,"Rename Failed: Name cannot be null");
            }
        });

    }

    @Override
    public boolean deleteKey(TreeItem<RedisTreeItem> selectedItem, RedisTreeItem value){
        boolean b = JavaFxUtil.showConfirmDialogYNC(LarkFrame.primaryStage, "删除确认", null, "是否确认删除KEY:" + ConfigParserUtils.getInstance().byteToStr(value.getKey()) + "？");
        if(b){
            ResultRes<Long> res = BaseController.dispatcher(() -> redisConnectService.deleteKeys(value.getId(), value.getDbAmount().getDbIndex(), value.getKey()));
            if(res.isRet()){
                value.setDelete(true);
                Event.fireEvent(selectedItem, new TreeItem.TreeModificationEvent<>(TreeItem.valueChangedEvent(), selectedItem, value));
                TreeItem<RedisTreeItem> parent = selectedItem.getParent();
                while (parent != null && parent.getValue() != null && !RedisTreeType.DATABASE.equals(parent.getValue().getType()) ){
                    parent = parent.getParent();
                }
                if(parent != null){
                    ResultRes<Long> resultRes = BaseController.dispatcher(() -> redisConnectService.getDbKeySize(value.getId(), value.getDbAmount().getDbIndex()));
                    if(resultRes.isRet()){
                        parent.getValue().getDbAmount().setDbSize(resultRes.getData());
                        parent.getValue().setName(parent.getValue().getDbAmount().toString());
                        parent.getValue().setOriginName( parent.getValue().getDbAmount().toString());
                        Event.fireEvent(parent, new TreeItem.TreeModificationEvent<>(TreeItem.valueChangedEvent(), parent, parent.getValue()));
                    }
                }
                ObservableList<Tab> tabs = RedisApplication.mainController.getMainInfoTabPane().getTabs();
                if(DataStructureUtils.isNotEmpty(tabs)){
                    Iterator<Tab> iterator = tabs.iterator();
                    while (iterator.hasNext()){
                        Tab tab  = iterator.next();
                        if(tab.getUserData() == value && "keyInfo".equals(tab.getProperties().get("type"))){
                            JavaFxUtil.closeTabRelease(RedisApplication.mainController.getMainInfoTabPane(),tab);
                            iterator.remove();
                        }
                    }
                }
                return true;

            }else{
                JavaFxUtil.showMessageErrorDialog(LarkFrame.primaryStage,null,res.getMsg());
            }
        }
        return false;
    }

    /**
     *
     * @param textInputControl 在文本選項下可編輯
     * @param dicBean
     * @param configNode
     * @return
     */
    @Override
    public String  getSelectDicText(TextInputControl textInputControl, DicBean dicBean, Node configNode){
        String text = (String) textInputControl.getProperties().get("text");
        textInputControl.setEditable(false);
        if(configNode  != null){
            configNode.setDisable(true);
        }
        if("1".equals(dicBean.getCode())){
            textInputControl.setEditable(true);
            if(textInputControl.getUserData() != null && configNode != null){
                configNode.setDisable(StringUtils.equals(text,textInputControl.getUserData().toString()));
            }
        }else if("2".equals(dicBean.getCode())){
            text = GsonUtil.toPrettyFormat(text);
            if(text.equals(textInputControl.getProperties().get("text"))){
                JavaFxUtil.showMessageErrorDialog(null,null,"Format Json Fail!");
            }
        }else if("3".equals(dicBean.getCode())){

        }else if("4".equals(dicBean.getCode())){
            text = StringUtils.bytesToHexString((byte[]) textInputControl.getProperties().get("textByte"), true);
        }
        textInputControl.setText(text);
        return text;
    }

    @Override
    public void editServer(TreeItem<RedisTreeItem> treeItem){
        if(treeItem == null){
            return;
        }
        if(DataStructureUtils.isNotEmpty(treeItem.getChildren())){
            boolean b = JavaFxUtil.showConfirmDialogYNC(LarkFrame.primaryStage, "编辑确认", null, "连接已打开，编辑将会关闭连接，是否继续？");
            if(!b){
                return;
            }
            RedisLarkPool.destory(treeItem.getValue().getId());
            treeItem.getChildren().clear();
            deleteServerTabs(treeItem.getValue());
        }
        RedisApplication.mainController.openAddServerDialog(redisConfigService.getRedisConfigById(treeItem.getValue().getId()));

    }
    @Override
    public void deleteServer(TreeItem<RedisTreeItem> treeItem){
        if(treeItem == null){
            return;
        }
        RedisTreeItem item = treeItem.getValue();
        boolean b = JavaFxUtil.showConfirmDialogYNC(LarkFrame.primaryStage,   "删除服务", null,"是否确认删除服务："+item.getName());
        if(b){
            ResultRes<RedisConnectInfo> res = BaseController.dispatcher(() -> redisConfigService.deleteRedisConfigById(item.getId()));
            if(res.isRet()){
                MainController mainController = RedisApplication.mainController;
                //删除树节点
                TreeItem<RedisTreeItem> parent = treeItem.getParent();
                treeItem.getChildren().clear();
                parent.getChildren().remove(treeItem);
                deleteServerTabs(item);
                RedisApplication.mainController.hasServerData();

            }else{
                JavaFxUtil.showMessageErrorDialog(LarkFrame.primaryStage,null,res.getMsg());
            }
        }
    }
    private void deleteServerTabs(RedisTreeItem item) {
        ObservableList<Tab> tabs = RedisApplication.mainController.getMainInfoTabPane().getTabs();
        if(DataStructureUtils.isNotEmpty(tabs)){
            Iterator<Tab> iterator = tabs.iterator();
            while (iterator.hasNext()){
                Tab tab  = iterator.next();
                if(tab.getUserData() instanceof RedisTreeItem  && ((RedisTreeItem)tab.getUserData()).getId().equals(item.getId())){
                    JavaFxUtil.closeTabRelease(RedisApplication.mainController.getMainInfoTabPane(),tab);
                    iterator.remove();
                }
            }
        }
    }

    @Override
    public Tab openServerInfoTab(TreeItem<RedisTreeItem> serverTreeItem) {
        try {
            RedisTreeItem value = serverTreeItem.getValue();
            TabPane mainInfoTabPane = RedisApplication.mainController.getMainInfoTabPane();
            Tab tab = new Tab(JavaFxUtil.tabString(value.getName()));
            tab.setTooltip(new Tooltip(value.getName()));
            FXMLLoader fxmlLoader = new FXMLLoader();
            BorderPane pane = JavaFxUtil.loadFxml(fxmlLoader,"/view/fxml/serverInfo.fxml");
            ServerInfoController controller = fxmlLoader.getController();
            ChangeListener<Number> widthChangeListener = (observable, oldValue, newValue) -> {
                pane.setPrefWidth(newValue.doubleValue());
                controller.getServerInfoBorderPane().setPrefWidth(newValue.doubleValue());

            };
            ChangeListener<Number> heightChangeListener = (observable, oldValue, newValue) -> {
//                pane.setPrefHeight(newValue.doubleValue());
            };
            tab.setOnClosed(event -> JavaFxUtil.closeTabRelease(mainInfoTabPane,tab));
            JavaFxUtil.tabBindChangeListener(tab,widthChangeListener,heightChangeListener);
            mainInfoTabPane.widthProperty().addListener(widthChangeListener);
            mainInfoTabPane.heightProperty().addListener(heightChangeListener);


            pane.setPrefHeight(mainInfoTabPane.getHeight());
            pane.setPrefWidth(mainInfoTabPane.getWidth());
            controller.getServerInfoBorderPane().setPrefWidth(mainInfoTabPane.getWidth());

            controller.initialize(serverTreeItem,tab);
            tab.setContent(pane);
            tab.setUserData(value);
            tab.getProperties().put("controller",controller);
            tab.getProperties().put("selectedItem",serverTreeItem);
            tab.getProperties().put("type","server");
            mainInfoTabPane.getTabs().add(tab);
            mainInfoTabPane.getSelectionModel().select(tab);
            return tab;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}
